/**
 * FyLLGen - A Java based tool for collecting and distributing family data
 *
 * Copyright (C) 2007-2011 Christian Packenius
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.chris_soft.fyllgen.export;

import java.awt.Desktop;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;

import de.chris_soft.fyllgen.GUI;
import de.chris_soft.fyllgen.Statics;
import de.chris_soft.fyllgen.data.Family;
import de.chris_soft.fyllgen.data.OptionData;
import de.chris_soft.fyllgen.data.Person;
import de.chris_soft.fyllgen.utilities.MailTools;
import de.chris_soft.fyllgen.utilities.SwtUtilities;

/**
 * Hier werden (egal welche) Daten per E-Mail exportiert.
 * @author Christian Packenius, 30.07.2011.
 */
public class PerMailExporter {
  final boolean shallUsePVFilter;

  final boolean createPrintVersion;

  final boolean zipPDF;

  final boolean shallSendMail;

  final List<Person> personList;

  final String simpleFilename;

  final DataExporter exporter;

  Person p0 = null;

  final Shell shell;

  final boolean automaticMailing;

  /**
   * Konstruktor.
   * @param shallUsePVFilter
   * @param createPrintVersion
   * @param zipPDF
   * @param shallSendMail
   * @param personList
   * @param simpleFilename
   * @param exporter
   * @param shell
   * @param automaticMailing
   */
  public PerMailExporter(boolean shallUsePVFilter, boolean createPrintVersion, boolean zipPDF, boolean shallSendMail,
      List<Person> personList, String simpleFilename, DataExporter exporter, Shell shell, boolean automaticMailing) {
    super();
    this.shallUsePVFilter = shallUsePVFilter;
    this.createPrintVersion = createPrintVersion;
    this.zipPDF = zipPDF;
    this.shallSendMail = shallSendMail;
    this.personList = personList;
    p0 = personList.get(0);
    this.simpleFilename = simpleFilename;
    this.exporter = exporter;
    this.shell = shell;
    this.automaticMailing = automaticMailing;
  }

  /**
   * Exportiert die Familie per E-Mail in einem eigenen Thread.
   */
  public void export() {
    Runnable runner = new ExportAndMailDataThread();
    ExportService.execute(runner);
    // Thread thread = new Thread(runner);
    // thread.setDaemon(false);
    // thread.start();
  }

  class ExportAndMailDataThread implements Runnable {
    /**
     * Running export and mailing in an extra thread.
     */
    public void run() {
      synchronized (PerMailExporter.class) {
        exportAndMail();
      }
    }

    /**
     * Content of Thread for exporting and mailing instance tree data.
     */
    private void exportAndMail() {
      boolean error = false;
      try {
        // Dateiendung ermitteln.
        String fileExtension = exporter.getFileExtension();

        // PDF-Bytearray erzeugen.
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        long documentNumber = exporter.export(personList, byteOut);

        if (zipPDF) {
          // Byte-Array in eine ZIP-Datei schreiben und per Mail versenden.
          new File(fileExtension).mkdir();
          String zipFilename = fileExtension + "/" + simpleFilename + "-" + documentNumber + ".zip";
          ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFilename));
          out.setLevel(9);
          out.putNextEntry(new ZipEntry(simpleFilename + "-" + documentNumber + "." + fileExtension));
          byteOut.writeTo(out);
          out.closeEntry();
          out.close();
          sendFamilyBookPerMail(zipFilename, documentNumber);
        }
        else {
          // Byte-Array in eine (normale PDF-) Datei schreiben und per Mail
          // versenden.
          new File(fileExtension).mkdir();
          String filename = fileExtension + "/" + simpleFilename + "-" + documentNumber + "." + fileExtension;
          FileOutputStream out = new FileOutputStream(filename);
          byteOut.writeTo(out);
          out.close();
          sendFamilyBookPerMail(filename, documentNumber);
        }
      }
      catch (Throwable exception) {
        error = true;
        exception.printStackTrace();
        SwtUtilities.sayError(GUI.instance.shell, "Fehler beim Schreiben der Export-Datei!");
      }
      if (!error) {
        // String msg = "Exportdatei erfolgreich erstellt.";
        if (shallSendMail && !automaticMailing) {
          String msg = "E-Mail wurde verschickt.";
          SwtUtilities.sayInfo(GUI.instance.shell, msg);
        }
      }
    }

    /**
     * Versendet die erzeugte und gezippte PDF-Datei per E-Mail.
     * @param documentNumber
     */
    private void sendFamilyBookPerMail(final String zipFilename, final long documentNumber) {
      if (shallSendMail) {
        final String mail = p0.getValue(Person.MAIL);
        sendMail(zipFilename, mail, documentNumber);
        Display.getDefault().syncExec(new Runnable() {
          public void run() {
            createMailingNote(mail, documentNumber);
          }
        });
      }
      else {
        Display.getDefault().syncExec(new Runnable() {
          public void run() {
            createExportNote(documentNumber);
            openFile(zipFilename);
          }

          private void openFile(String zipFilename) {
            if (Desktop.isDesktopSupported()) {
              Desktop dt = Desktop.getDesktop();
              try {
                dt.open(new File(zipFilename));
              }
              catch (Exception ex) {
                ex.printStackTrace();
              }
            }
          }
        });
      }
    }

    /**
     * Send mail with ZIP-File to given mail address.
     */
    private void sendMail(String zipFilename, String mail, long documentNumber) {
      MailTools mt = new MailTools();
      String from = OptionData.instance.getString(OptionData.EXPORT_MAIL);
      String subject = OptionData.instance.getString(OptionData.EXPORT_TITLE).replace("#TITLE#", "" + documentNumber);
      String password = OptionData.instance.getExportPassword(true);
      String text = OptionData.instance.getString(OptionData.EXPORT_TEXT);
      mt.setFrom(from);
      mt.setPassword(password);
      mt.setSubject(subject);
      mt.setText(text);
      mt.addTO(mail);
      mt.addAttachment(zipFilename);
      boolean sendMailError = false;
      try {
        if (!mt.sendMail()) {
          sendMailError = true;
        }
      }
      catch (Exception exc) {
        sendMailError = true;
      }
      if (sendMailError) {
        Display.getDefault().syncExec(new Runnable() {
          public void run() {
            MessageBox mb;
            mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR | SWT.APPLICATION_MODAL);
            mb.setText("Fehler!");
            mb.setMessage("Es gab Probleme beim Versenden der E-Mail!");
            mb.open();
          }
        });
      }
    }

    /**
     * Write a note in the personal notes that the mail has been sent.
     */
    void createMailingNote(String mail, long documentNumber) {
      String notes = p0.getValueView(Person.NOTES);
      while (notes.length() > 0 && " \t\r\n".indexOf(notes.charAt(notes.length() - 1)) >= 0) {
        notes = notes.substring(0, notes.length() - 1);
      }
      if (notes.length() > 0) {
        notes += "\r\n\r\n";
      }
      notes += Statics.today() + ":\r\n" + "PDF-Datei #" + documentNumber + " mit Familienstammbaum an " + mail
          + " verschickt.";
      p0.setValue(Person.NOTES, notes);
      p0.addTag("PDF-Mail: " + Statics.todayYYYY_MM());
      Family.instance.review();
    }

    /**
     * Write a note in the personal notes that the export has been made.
     */
    void createExportNote(long documentNumber) {
      String notes = p0.getValueView(Person.NOTES);
      while (notes.length() > 0 && " \t\r\n".indexOf(notes.charAt(notes.length() - 1)) >= 0) {
        notes = notes.substring(0, notes.length() - 1);
      }
      if (notes.length() > 0) {
        notes += "\r\n\r\n";
      }
      notes += Statics.today() + ":\r\n" + "PDF-Datei #" + documentNumber + " mit Familienstammbaum erzeugt.";
      p0.setValue(Person.NOTES, notes);
      Family.instance.review();
    }
  }
}
